/*
* Copyright (C) Microsoft. All rights reserved.  
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not 
* use this file except in compliance with the License.  You may obtain a copy 
* of the License at http://www.apache.org/licenses/LICENSE-2.0  
* 
* THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 
* WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 
* MERCHANTABLITY OR NON-INFRINGEMENT. 
*
* See the Apache License, Version 2.0 for specific language governing 
* permissions and limitations under the License.
*
*/
#pragma once

#include <baja/common.hpp>
#include <baja/graphics.hpp>
#include <baja/graphics/scenes.hpp>
#include <baja/app/input.hpp>
#include <baja/app/debug_console.hpp>
#include <journal/views/interfaces.h>
#include <journal/app/constants.h>
#include <journal/views/scene_state.h>

namespace journal { namespace view {

namespace b = baja;
namespace a = baja::app;
namespace g = baja::graphics;
namespace gs = baja::graphics::scenes;
namespace gd = baja::graphics::dx11_1::details;

class scene_references : 
    public iscene_references, 
    public std::enable_shared_from_this<scene_references>
{
    enum class state
    {
        none,
        idle,
        changingRotation,
        changingPosition,
        changingDistance,
        changingFocus,
        changingLightRotation
    };

public:
    scene_references(
        const std::shared_ptr<a::iinput_capture>& inputCapture,
        scene_state* sceneState
        );

    static std::shared_ptr<scene_references> create(
        const std::shared_ptr<a::iinput_capture>& inputCapture,
        scene_state* sceneState
        )
    {
        std::shared_ptr<scene_references> returnValue = std::make_shared<scene_references>(inputCapture, sceneState);
        return returnValue->shared_from_this();
    }

    // iscene_references
    void setVisible(const bool visible) { _visible = visible; }
    bool visible() { return _visible; }

    // irender_observer
    void onRender();
    void onScreenChange(const a::screen_change_args& args) { /* noop */ };
    void onResize(const a::resize_args& args) { /* noop */}
    void onVisibilityChanged(const bool visible) { /* noop */ }

    // iinput_observer
    void onGesture(const a::gesture_args& args, void* context) { /*noop*/}
    void onPointer(const a::pointer_args& args, void* context = nullptr);
    void onKey(const a::key_args& args, void* context);

private:
    void renderDisclaimer();
    void renderAxes();
    void renderFloor();
    void renderLight();
    void renderFPS();
    void renderFocus();
    void updateDebugString();

private:
    std::shared_ptr<g::ifont> _font;
    scene_state* _sceneState;
    state _state;
    m::point2d _startPoint;
    m::vector3d _startAngles;
    m::vector2d _startPosition;
    b::float32 _startDistance;
    m::vector2d _startFocus;
    bool _down;
    std::weak_ptr<a::iinput_capture> _inputCapture;
    bool _visible;
    bool _renderDisclaimer;

    m::vector3d _restoreAngles;
    b::float32 _restoreDistance;
    m::vector2d _restoreFocus;
    m::vector2d _restorePosition;

    std::vector<b::wchar> _debugString;
    static const b::uint32 max_debug_string = 256;

    static const b::wchar* c_platform;
    static const b::wchar* c_config;
};

inline std::shared_ptr<iscene_references> createSceneReferences(
    const std::shared_ptr<a::iinput_capture>& inputCapture,
    scene_state* sceneState
    )
{
    std::shared_ptr<scene_references> returnValue = scene_references::create(inputCapture, sceneState);
    return std::static_pointer_cast<iscene_references>(returnValue);
}

}} // namespace journal::view